package com.dianping;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.TreeMap;

import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.Tokenizer;

public class CnTokenizer extends Tokenizer{
	      
	    /** 
	     * 用来缓存词典里所有的词 
	     */  
	    private TreeMap<String, String> allWordsMap ;  
	      
	    /** 
	     * 读入的所有文本(待分词的文本) buffer 
	     */  
	    StringBuffer textBuffer = null ;  
	      
	    /** 
	     * 读入的所有文本(待分词的文本) string 
	     */  
	    private String text = null ;  
	      
	    /** 
	     * 要分词的文本字符的长度 
	     */  
	    private int textLength ;  
	      
	      
	    /** 
	     * 存放token序列的序列 
	     */  
	    private List<Token> allTokenList = null ;  
	      
	    /** 
	     * token序列的迭代 
	     */  
	    private Iterator<Token> allTokenIter = null ;  
	      
	    /** 
	     * 匹配当前的字符串偏移量 
	     */  
	    private int curIndex = 0 ;  
	      
	    /** 
	     * 最长词的长度 
	     */  
	    private static int MAX_WORD_LENGTH = 10 ;  
	      
	    /** 
	     * 切词的长度 
	     */  
	    private int cutLength = 0  ;  
	      
	     /**
	      *词典位置 
	      * 
	      */
	    private String pathName = "C:\\Users\\sky\\workspace\\sDict.txt";
	    
	    public CnTokenizer(Reader input){  
	        this.input = input ;  
	        try{  
	            //初始化  
	            init() ;  
	            //正向最大匹配  
	            doCutForward() ;  
	            //逆向的最大匹配  
	            //doCutBackward() ;  
	              
	            allTokenIter = allTokenList.iterator() ;  
	        }catch(Exception e){  
	            e.printStackTrace() ;  
	        }  
	    }  
	      
	    /** 
	     * 初始化数据 
	     * 导入词库 
	     * 读出要分词的字符串 
	     * 
	     */  
	    public void init() throws IOException{  
	        //导入词库  
	        loadWords() ;  
	          
	        //读入要分词的文本  
	        textBuffer = new StringBuffer() ;  
	        BufferedReader br = new BufferedReader(input) ;  
	        String temp = null ;  
	        while(true){  
	            if((temp = br.readLine())!= null){  
	                textBuffer.append(temp) ;  
	            }else{  
	                break ;  
	            }  
	            text = new String(textBuffer) ;  
	            textLength = textBuffer.length() ;  
	        }  
	        allTokenList = new ArrayList<Token>() ;  
	    }  
	      
	    /** 
	     * 正向最大匹配 
	     */  
	    public void doCutForward(){  
	        //开始的时候从0开始  
	        curIndex = 0 ;  
	        while(curIndex < textLength){  
	            //如果切词长度为0，则设定切词长度  
	            if(cutLength == 0 ){  
	                //设定正向的切词长度  
	                setCutForwardLength() ;  
	            }  
	            int startIndex = curIndex;  
	            int endIndex = curIndex + cutLength;  
	            String temp = textBuffer.substring(startIndex , endIndex) ;  
	            //如果存在这个词,将偏移量移动这个词的距离  
	            if(allWordsMap.containsKey(temp)){  
	                Token tk = new Token(temp,startIndex,endIndex) ;  
	                allTokenList.add(tk) ;  
	                curIndex += cutLength ;  
	                //将切词长度置零，下次循环时可以重新设定长度  
	                cutLength = 0 ;  
	            }else{  
	                //如果不存在这个词，则将切词长度减1  
	                cutLength -- ;  
	                if(cutLength == 0){  
	                    curIndex++ ;  
	                    cutLength =0 ;  
	                }  
	            }  
	        }  
	    }  
	      
	    /** 
	     * 逆向最大匹配 
	     */  
	    public void doCutBackward(){  
//	      开始的时候从最后的索引开始  
	        curIndex = textLength ;  
	        while(curIndex > 0){  
	            //如果切词长度为0，则设定切词长度  
	            if(cutLength == 0 ){  
	                //设定逆向的切词长度  
	                setCutBackwardLength() ;  
	            }  
	            int startIndex = curIndex - cutLength;  
	            int endIndex = curIndex;  
	            String temp = textBuffer.substring(startIndex , endIndex) ;  
	            //如果存在这个词,将偏移量向前移动这个词的距离  
	            if(allWordsMap.containsKey(temp)){  
	                Token tk = new Token(temp,startIndex,endIndex) ;  
	                allTokenList.add(tk) ;  
	                curIndex -= cutLength ;  
	                //将切词长度置零，下次循环时可以重新设定长度  
	                cutLength = 0 ;  
	            }else{  
	                //如果不存在这个词，则将切词长度减1  
	                cutLength -- ;  
	                if(cutLength == 0){  
	                    curIndex-- ;  
	                    //将切词长度置零，下次循环时可以重新设定长度  
	                    cutLength = 0 ;  
	                }  
	            }  
	        }  
	    }  
	      
	    /** 
	     * 设定正向最大匹配的切词长度 
	     * 
	     */  
	    private void setCutForwardLength(){  
	        //如果文本长度没有达到设定的最大长度，那么直接从文本最后开始切  
	        if(textLength <= MAX_WORD_LENGTH){  
	            //文本长度没有达到设定的最大长度，切词长度从文本的长度开始  
	            cutLength = textBuffer.length() ;  
	        }else{  
	            //文本长度达到设定的最大长度，切词长度从设定的最大长度开始  
	            cutLength = MAX_WORD_LENGTH ;  
	        }  
	        //如果切词长度大于从当前偏移量到文本最后的长度，那么切词长度应该是最后剩下的文本长度  
	        if(cutLength > textLength - curIndex){  
	            cutLength =textLength - curIndex ;  
	        }  
	          
	          
	    }  
	      
	    /** 
	     * 设定逆向最大匹配的切词长度 
	     * 
	     */  
	    private void setCutBackwardLength(){  
	        //如果文本长度没有达到设定的最大长度，那么切词长度就是文本长度  
	        if(textLength <= MAX_WORD_LENGTH){  
	            //文本长度没有达到设定的最大长度，切词长度从文本的长度开始  
	            cutLength = textBuffer.length() ;  
	        }else{  
	            //文本长度达到设定的最大长度，切词长度从设定的最大长度开始  
	            cutLength = MAX_WORD_LENGTH ;  
	        }  
	        //如果当前偏移量小于切词长度，则切词长度应该是偏移量  
	        if(cutLength > curIndex){  
	            cutLength = curIndex ;  
	        }  
	          
	          
	    }  
	      
	      
	    public Token next() throws IOException{  
	        while(allTokenIter.hasNext()){  
	            return allTokenIter.next() ;  
	        }  
	        return null ;  
	    }  
	      
	    /*导入词库*/  
	    public void loadWords(){  
	        if(allWordsMap != null){  
	            return ;  
	        }  
	        allWordsMap = new TreeMap<String,String>() ;  
	        try{  
	            //File file = new File("sDict.txt") ;  
	        	File file = new File(pathName);
	            //System.out.println(file.getAbsolutePath()) ;  
	            InputStream words = new FileInputStream(file) ;  
	            BufferedReader in = new BufferedReader(new InputStreamReader(words,"UTF-8")) ;  
	            String word = null ;  
	            while((word = in.readLine())!=null){  
	                allWordsMap.put(word, "key")  ;  
	            }  
	        }catch(IOException e){  
	            e.printStackTrace() ;  
	        }  
	    }  
	      
	      
	    public static void main(String [] args){  
	        long stime = System.currentTimeMillis() ;  
	        StringReader sr = new StringReader("逃犯成功越狱，警方将展开追踪调查") ;  
	        Tokenizer xt = new CnTokenizer(sr) ;  
	        Token t = null ;  
	        try{  
	            while((t=((CnTokenizer) xt).next())!=null){  
	                System.out.println(t) ;  
	            }  
	        }catch(Exception e){  
	            e.printStackTrace() ;  
	        }  
	        long etime = System.currentTimeMillis() ;  
	        System.out.println("用时:" + (double)(etime-stime)/1000);  
	    }

		@Override
		public boolean incrementToken() throws IOException {
			// TODO Auto-generated method stub
			return false;
		}  
	      
	      
}
